/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package hibernate;

import beans.Nodo;
import beans.Pareja;
import beans.Usuario;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.Transaction;

/** Clase NodoBD : clase para operaciones en la base de datos referentes a los
 * nodos.
 *
 *
 */
public class NodoBD extends PreparacionHibernate {

    private Nodo nodo;

    /**Constructor de la clase
     */
    public NodoBD(Nodo nodo) {
        this.nodo = nodo;
    }

    /**Metodos observadores y modificadores de la clase.
     */
    public Nodo getNodo() {
        return nodo;
    }

    public void setNodo(Nodo nodo) {
        this.nodo = nodo;
    }

    /**Metodo devuelveNodosHijos: devuelve todos los hijos que esten en la base 
     * de datos del atributo nodo. 
     * @return Set: conjunto con todos los hijos
     * 
     */
    public Set devuelveNodosHijos() {
        //Primero encuentra todas la parejas del nodo
        List<Object> lista = devuelveParejas();
        //Se itera sobre todas las parejas para obtener todos los hijos de
        //todas las parejas.
        Set hijos = new HashSet();
        for (Object object : lista) {
            Pareja pareja = (Pareja) object;
            ParejaBD parejaBD = new ParejaBD(pareja);
            hijos.addAll(parejaBD.devuelveHijos());
        }

        return hijos;
    }

    /**Metodo recuperarNodo: recupera el nodo de la base de datos cuyo idNodo
     * sea igual que el del nodo atributo.Esto se hace para actualizar el nodo.
     * @return Nodo : el nodo que estamos tratando tal como está en la
     * base de datos.
     */
    public Nodo recuperaNodo() {

        long idNodo = nodo.getIdNodo();
        String query = "FROM Nodo WHERE idNodo = :idNodo";
        Hashtable<String, Object> ht = new Hashtable<String, Object>();
        ht.put("idNodo", idNodo);
        try {
            nodo = (Nodo) devuelveDatos(query, ht).get(0);
        } catch (NullPointerException ne) {
        }

        return nodo;
    }

    /**Metodo devuelveNodoParejas: devuelve un set con las parejas del nodo
    @return Set : las parejas del nodo.
     */
    public Set devuelveNodoParejas() {
        //Obtengo una lista de parejas llamando a la funcion devuelveParejas.
        List<Object> lista = devuelveParejas();
        //Creo el set con los nodos pareja de mi nodo atributo , llamando a la
        //funcion cunstruyeSetParejas.
        Set parejas = construyeSetParejas(lista);
        return parejas;
    }

    /**Metodo devuelveParejas: devuelve una lista de Parejas del Nodo
     * @return List: lista de las parejas del nodo (objetos de la clase Pareja).
     */
    private List<Object> devuelveParejas() {
        //Consulta: todas la parejas de las que mi nodo forme parte.
        String query = "FROM Pareja WHERE idComponenteUno = :idComp1 OR idComponenteDos = :idComp2";
        Hashtable<String, Object> hashtable = new Hashtable<String, Object>();
        hashtable.put("idComp1", nodo.getIdNodo());
        hashtable.put("idComp2", nodo.getIdNodo());
        List<Object> lista = devuelveDatos(query, hashtable);
        return lista;
    }

    /**Metodo construyeSetParejas: crea un set de Nodos a partir de una lista de 
     * Parejas. Estos nodos seran los nodos de cada pareja que no son el propio nodo atributo
     *@param List<Object>: lista de Parejas del atributo nodo
     * @return Set: conjunto de nodos , que son las parejas del atributo nodo.
     */
    private Set construyeSetParejas(List<Object> lista) {

        Set conjunto = new HashSet();

        for (Object object : lista) {
            Pareja pareja = (Pareja) object;
            if (pareja.getComponente1().getIdNodo() == nodo.getIdNodo()) {
                conjunto.add(pareja.getComponente2());
            } else {
                conjunto.add(pareja.getComponente1());
            }
        }

        return conjunto;
    }

    /**Metodo actualizaNodo: recupera el nodo pasado como parametro de la base de datos
     * y lo actualiza con los datos del nodo atributo.
     *@param String : si o no dependiendo si el nodo debe tener fecha de defuncion
     * @param Nodo : Nodo que vamos a actualizar.
     * @return Nodo: Nodo actualizado.
     */
    public Nodo actualizaNodo(String muerto, Nodo nodoAnterior) {
        long id = nodoAnterior.getIdNodo();
        Session sesion = getSesion();
        Transaction trans = sesion.beginTransaction();

        Nodo nodoAux = (Nodo) sesion.load(Nodo.class, id);
        nodoAux.setApellidos(nodo.getApellidos());
        nodoAux.setNombre(nodo.getNombre());
        nodoAux.setFechaNacimiento(nodo.getFechaNacimiento());
        if (muerto.equals("si")) {
            nodoAux.setFechaDefuncion(nodo.getFechaDefuncion());
        } else if (muerto.contains("no")) {
            nodoAux.setFechaDefuncion(null);
        } else {
            nodoAux.setFechaDefuncion(nodoAnterior.getFechaDefuncion());
        }


        trans.commit();
        sesion.close();

        return nodoAux;
    }

    /**
    Devuelve un Nodo a partir de su id
     * @param id Id del nodo a recuperar
     * @return Devuelve el nodo determinado por el id
     * <p><b>Ejemplo:</b></p>
     * NodoBD nodoBD = new NodoBD(nodo);<br/>
     * Nodo miNodo =nodoBD (nodo.getIdNodo());
     */
    public Nodo devuelveNodo(long id) {
        Nodo n = null;
        List<Object> lista;


        //No lo hacemos con load porque el Nodo que devuelve es de tipo raro y no
        //contiene todos los atributos rellenos
        try {
            String query = "FROM Nodo WHERE idNodo = :idNodo";
            Hashtable<String, Object> ht = new Hashtable<String, Object>();
            ht.put("idNodo", id);

            lista = devuelveDatos(query, ht);
            n = (Nodo) lista.get(0);

        } catch (NullPointerException npe) {
        }
        return n;
    }

    /**Metodo anadir: añade el nodo atributo en la base de datos.
     */
    public void anadir() {
        //llama a la funcion generica anadirEnBD de la clase PreparacionHibernate.
        anadirEnBD(nodo);
    }
    
    public Nodo actualizaNodo(Usuario u, Nodo nodoAnterior) {
        long id = nodoAnterior.getIdNodo();
        Session sesion = getSesion();
        Transaction trans = sesion.beginTransaction();

        Nodo nodoAux = (Nodo) sesion.load(Nodo.class, id);
        nodoAux.setUsuario(u);
        
        trans.commit();
        sesion.close();

        return nodoAux;
    }
}
